﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 蚂蚁信息素感知地图，用于记录和获取信息素的分布情况
public class PerceptionMap : MonoBehaviour {

    // 区域大小（二维）
	public Vector2 area;

    // 蚂蚁的参数配置（如感知半径、信息素持续时间等）
	public AntSettings antSettings;

    // 用于可视化信息素的粒子系统
	public ParticleSystem particleDisplay;

    // 粒子发射参数
	ParticleSystem.EmitParams particleEmitParams;

    // 感知半径的平方值（用于距离比较）
	float sqrPerceptionRadius;

    // 信息素颜色
	public Color pheremoneColor;

    // 信息素粒子大小
	public float pheremoneSize = 0.05f;

    // 初始透明度（alpha值）
	public float initialAlpha = 1;

    // 网格中X方向的单元格数量
	int numCellsX;

    // 网格中Y方向的单元格数量
	int numCellsY;

    // 区域中心的一半尺寸，用于坐标换算
	Vector2 halfSize;

    // 单元格大小的倒数
	float cellSizeReciprocal;

    // 信息素存储的二维网格
	Cell[, ] cells;

    // 脚本启动时自动调用的初始化函数
	void Awake () {
		Init ();
	}

    // 每帧调用，更新粒子参数
	void Update () {
        // 每帧更新粒子的生存时间
		particleEmitParams.startLifetime = antSettings.pheromoneEvaporateTime;
	}

    // 初始化网格、粒子系统等
	void Init () {
        // 读取蚂蚁的感知半径，至少为 0.01
		float perceptionRadius = Mathf.Max (0.01f, antSettings.sensorSize);
        // 感知半径的平方值（用于距离比较）
		sqrPerceptionRadius = perceptionRadius * perceptionRadius;

        // 创建网格地图计算网格行列数
		numCellsX = Mathf.CeilToInt (area.x / perceptionRadius);
		numCellsY = Mathf.CeilToInt (area.y / perceptionRadius);

        // 计算一半尺寸
		halfSize = new Vector2 (numCellsX * perceptionRadius, numCellsY * perceptionRadius) * 0.5f;
		cellSizeReciprocal = 1 / perceptionRadius;

        // 创建网格数组
		cells = new Cell[numCellsX, numCellsY];

        // 初始化每一个格子
		for (int y = 0; y < numCellsY; y++) {
			for (int x = 0; x < numCellsX; x++) {
				cells[x, y] = new Cell ();
			}
		}

        // 初始化粒子参数
		particleEmitParams.startLifetime = antSettings.pheromoneEvaporateTime;
		particleEmitParams.startSize = pheremoneSize;

        // 设置粒子系统的最大粒子数量
		var m = particleDisplay.main;
		m.maxParticles = 100 * 1000;

        // 配置颜色随时间变化
		var c = particleDisplay.colorOverLifetime;
		c.enabled = true;

        // 设置渐变颜色
		Gradient grad = new Gradient ();
		grad.colorKeys = new GradientColorKey[] {
            new GradientColorKey (Color.white, 0),
            new GradientColorKey (Color.white, 1)
        };
		grad.alphaKeys = new GradientAlphaKey[] {
            new GradientAlphaKey (initialAlpha, 0.0f),
            new GradientAlphaKey (0.0f, 1.0f)
        };

        // 应用颜色渐变
		c.color = grad;
	}

    // 添加一个新的信息素记录（在特定位置）
	public void Add (Vector2 point, float initialWeight) {
        // 计算所在格子
		Vector2Int cellCoord = CellCoordFromPos (point);
		Cell cell = cells[cellCoord.x, cellCoord.y];

        // 构造信息素条目
		Entry entry = new Entry () {
            position = point,
            creationTime = Time.time,
            initialWeight = initialWeight
        };

        // 添加到格子中
		cell.Add (entry);

        // 发射粒子表示信息素
		particleEmitParams.startColor = new Color (
            pheremoneColor.r, pheremoneColor.g, pheremoneColor.b, initialWeight
        );
		particleEmitParams.position = point;
		particleDisplay.Emit (particleEmitParams, 1);
	}

    // 获取感知范围内的所有信息素条目，返回填入的数量
	public int GetAllInCircle (Entry[] result, Vector2 centre) {
		Vector2Int cellCoord = CellCoordFromPos (centre);
		int i = 0;
		float currentTime = Time.time;

        // 检查周围的9个格子（包括自身）
		for (int offsetY = -1; offsetY <= 1; offsetY++) {
			for (int offsetX = -1; offsetX <= 1; offsetX++) {
				int cellX = cellCoord.x + offsetX;
				int cellY = cellCoord.y + offsetY;

                // 检查格子是否在范围内
				if (cellX >= 0 && cellX < numCellsX && cellY >= 0 && cellY < numCellsY) {
					Cell cell = cells[cellX, cellY];

                    // 遍历该格子内的所有信息素
					var currentEntryNode = cell.entries.First;
					while (currentEntryNode != null) {
						Entry currentEntry = currentEntryNode.Value;
						float currentLifetime = currentTime - currentEntry.creationTime;

                        // 如果过期就删除
						if (currentLifetime > antSettings.pheromoneEvaporateTime) {
							cell.entries.Remove (currentEntryNode);
						}
                        // 在感知半径内就加入结果
						else if ((currentEntry.position - centre).sqrMagnitude < sqrPerceptionRadius) {
							if (i >= result.Length) {
								return result.Length;
							}
							result[i] = currentEntry;
							i++;
						}
						currentEntryNode = currentEntryNode.Next;
					}
				}
			}
		}
		return i;
	}

    // 把世界坐标转换为网格索引
	Vector2Int CellCoordFromPos (Vector2 point) {
		int x = (int) ((point.x + halfSize.x) * cellSizeReciprocal);
		int y = (int) ((point.y + halfSize.y) * cellSizeReciprocal);
		return new Vector2Int (Mathf.Clamp (x, 0, numCellsX - 1), Mathf.Clamp (y, 0, numCellsY - 1));
	}

	// 可选调试绘图函数（在编辑器中可启用查看网格）
	/*
	void OnDrawGizmosSelected () {
		if (!Application.isPlaying) {
			Init ();
		}
		Vector2Int selected = CellCoordFromPos (transform.position);
		float width = cells.GetLength (0) * perceptionRadius;
		float height = cells.GetLength (1) * perceptionRadius;
		for (int y = 0; y < cells.GetLength (1); y++) {
			for (int x = 0; x < cells.GetLength (0); x++) {
				float centreX = -width / 2 + x * perceptionRadius + perceptionRadius / 2;
				float centreY = -height / 2 + y * perceptionRadius + perceptionRadius / 2;
				Gizmos.color = new Color (1, 1, 1, 0.1f);
				Gizmos.DrawWireCube (new Vector3 (centreX, centreY), new Vector3 (perceptionRadius, perceptionRadius));

				for (int offsetY = -1; offsetY <= 1; offsetY++) {
					for (int offsetX = -1; offsetX <= 1; offsetX++) {
						if (selected.x + offsetX == x && selected.y + offsetY == y) {
							if (offsetX == 0 && offsetY == 0) {
								Gizmos.color = new Color (1, 0, 0, 0.3f);
							} else {
								Gizmos.color = new Color (1, 0, 0, 0.1f);
							}
							Gizmos.DrawCube (new Vector3 (centreX, centreY), new Vector3 (perceptionRadius, perceptionRadius));
						}
					}
				}
			}
		}
		Gizmos.color = Color.green;
		Gizmos.DrawWireSphere (transform.position, perceptionRadius);
	}
	*/

    // 每个格子存储一系列信息素条目
	public class Cell {
		public LinkedList<Entry> entries;

		public Cell () {
			entries = new LinkedList<Entry> ();
		}

        // 向链表添加新条目
		public void Add (Entry entry) {
			entries.AddLast (entry);
		}
	}

    // 表示一个信息素的条目
	public struct Entry {
		public Vector2 position;      // 位置信息
		public float initialWeight;   // 初始强度
		public float creationTime;    // 产生的时间
	}
}
